package com.ajk.server.service.impl;
import java.util.List;
import java.util.regex.Pattern;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.joda.time.DateTime;
import org.joda.time.Seconds;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Base64Utils;

import com.ajk.message.service.SmsSendService;
import com.ajk.server.dao.SmsVerificationMapper;
import com.ajk.server.dao.UsersMapper;
import com.ajk.server.exception.AjkException;
import com.ajk.server.exception.ErrorConstant;
import com.ajk.server.model.SmsVerification;
import com.ajk.server.model.Users;
import com.ajk.server.model.query.SmsVerificationQuery;
import com.ajk.server.model.request.GenerateVerCode;
import com.ajk.server.model.request.SmsType;
import com.ajk.server.service.SmsVerificationService;
import com.ajk.server.utils.CryptoUtil;
import com.ajk.server.utils.JSON;
import com.ajk.server.utils.ValidatorUtil;
import com.google.gson.JsonObject;

/**
 * 短信验证码  <br>
 * t_sms_verification <br>
 * v1.0 2016-05-01
 */
@Service
public class SmsVerificationServiceImpl implements SmsVerificationService {

	private static final Logger logger = LoggerFactory.getLogger(SmsVerificationServiceImpl.class);

	@Autowired
	private SmsVerificationMapper smsVerificationMapper;

	@Autowired
	Environment env;
	
	@Autowired
	UsersMapper usersMapper;

	@Autowired
	@Qualifier("smsSendService")
	SmsSendService smsSendService;
	/**
	 *根据ID删除 短信验证码
	 */
	@Override
	public Integer deleteSmsVerificationById(Integer id){
		return smsVerificationMapper.deleteById(id);
	}

	/**
	 *新增 短信验证码
	 */
	@Override
	@Transactional
	public Integer batchInsertSmsVerification(List<? extends SmsVerification> smsVerifications){
		Integer count = smsVerificationMapper.batchInsert(smsVerifications);
		return count;
	}
	/**
	 *新增 短信验证码
	 */
	@Override
	@Transactional
	public Integer insertSmsVerification(SmsVerification domain){
		Integer id = smsVerificationMapper.insert(domain);
		return id;
	}

	/**
	 *更新 短信验证码
	 */
	@Override
	@Transactional
	public Integer updateSmsVerification(SmsVerification domain){
		Integer count = smsVerificationMapper.update(domain);
		return count;
	}

	/**
	 *根据ID查询 短信验证码
	 */
	public SmsVerification findSmsVerificationById(Integer id){
		SmsVerification result = smsVerificationMapper.findById(id);
		if(result!=null){
			result.dealWith();
		}
		return result;
	}

	/**
	 *通过query 查询 短信验证码
	 */
	public List<SmsVerification> findSmsVerificationByQuery(SmsVerificationQuery query){
		query.dealWith();
		List<SmsVerification> result = smsVerificationMapper.findByQuery(query);
		if(CollectionUtils.isNotEmpty(result)) {
			for (SmsVerification smsVerification : result) {
				smsVerification.dealWith();
			}
		}
		return result;
	}	

	/**
	 *通过query count总条数
	 */
	public Integer countSmsVerificationByQuery(SmsVerificationQuery query){
		query.dealWith();
		Integer result = smsVerificationMapper.countByQuery(query);
		return result;
	}

	/**
	 * 通过ids查询
	 */
	public List<SmsVerification> findSmsVerificationByIds(List<Integer> ids){
		List<SmsVerification> result = smsVerificationMapper.findByIds(ids);
		if(CollectionUtils.isNotEmpty(result)) {
			for (SmsVerification smsVerification : result) {
				smsVerification.dealWith();
			}
		}
		return result;
	}


	private String validateGenerateVerCodeReturnMobileNo(String deviceId,Integer smsType,String para){
		if(StringUtils.isEmpty(deviceId)){
			AjkException exception = new AjkException(ErrorConstant.PARAM_ERROR.getErrorCode(),"deviceId不能为空");
			logger.error("短信验证获取失败",exception);
			throw exception;
		}
		if(smsType==null || (smsType!=SmsType.REGISTER && smsType!=SmsType.RESET_PASSWORD)){
			AjkException exception = new AjkException(ErrorConstant.PARAM_ERROR.getErrorCode(),"smsType为空或超出范围");
			logger.error("短信验证获取失败",exception);
			throw exception;
		}
		if(StringUtils.isEmpty(para)){
			AjkException exception = new AjkException(ErrorConstant.PARAM_ERROR.getErrorCode(),"para不能为空");
			logger.error("短信验证获取失败",exception);
			throw exception;
		}
		String paraJson = new String(Base64Utils.decode(para.getBytes()));
		JsonObject jsonObject = JSON.fromString(paraJson);
		//para:{"mobile":"18714329856","deviceId":"1234567e435"}
		String mobile = null;
		String deviceIdInEncoder = null;
		if(jsonObject.has("mobile")){
			mobile = jsonObject.get("mobile").getAsString();
		}
		if(jsonObject.has("deviceId")){
			deviceIdInEncoder = jsonObject.get("deviceId").getAsString();
		}
		if(StringUtils.isEmpty(mobile) || StringUtils.isEmpty(deviceIdInEncoder) ){
			AjkException exception = new AjkException(ErrorConstant.PARAM_ERROR.getErrorCode(),"para格式错误");
			logger.error("短信验证获取失败",exception);
			throw exception;
		}
		if(!Pattern.matches(ValidatorUtil.mobilePattern, mobile)) {
			AjkException exception = new AjkException(ErrorConstant.PARAM_ERROR.getErrorCode(),"手机号格式不合法");
			logger.error("短信验证获取失败",exception);
			throw exception;
		}
		if(!deviceId.equalsIgnoreCase(deviceIdInEncoder)){
			AjkException exception = new AjkException(ErrorConstant.PARAM_ERROR.getErrorCode(),"deviceId不正确");
			logger.error("短信验证获取失败",exception);
			throw exception;
		}
		return mobile;
	}

	//发送短信验证码
	@Override
	public Integer generateVerificationCode(GenerateVerCode generateVerCode) {
		String deviceId = generateVerCode.getDeviceId();
		Integer smsType = generateVerCode.getSmsType();
		String para = generateVerCode.getPara();
		//String mobile = validateGenerateVerCodeReturnMobileNo(deviceId,smsType,para);
		if(generateVerCode.getMobile() == null){
			throw  new AjkException(ErrorConstant.OPERATION_ERROR.getErrorCode(),"手机号码不能为空");
		}
		String mobile = generateVerCode.getMobile();
		
		Users users = usersMapper.findByMobile(mobile);
		if (null != smsType && smsType==SmsType.REGISTER && users!=null) {
			AjkException exception = new AjkException(ErrorConstant.ACCOUNT_EXISTS.getErrorCode(),"手机号码已经注册,请直接登录.");
			logger.error("短信验证获取失败",exception);
			throw exception;
		} else if(null != smsType && smsType == SmsType.RESET_PASSWORD && users==null){
			AjkException exception = new AjkException(ErrorConstant.OPERATION_ERROR.getErrorCode(),"手机号对应的用户不存在");
			logger.error("短信验证获取失败",exception);
			throw exception;
		}
		SmsVerification smsVerification = smsVerificationMapper.findLastByMobile(mobile);
		if (smsVerification != null) {
			DateTime lastRequestTime = new DateTime(smsVerification.getCreateTime());
			DateTime now = DateTime.now();
			int interval = Integer.parseInt(env.getProperty("config.verification_code_request_interval"));
			if(Seconds.secondsBetween(lastRequestTime, now).getSeconds() < interval){
				AjkException exception = new AjkException(ErrorConstant.OPERATION_ERROR.getErrorCode(),"请求短信验证码过于频繁，请稍后再试");
				logger.error("短信验证获取失败",exception);
				throw exception;
			}
		}
		
		int length = Integer.parseInt(env.getProperty("config.verification_code_len"));
	    int expiration = Integer.parseInt(env.getProperty("config.verification_code_expiration"));
	    
	    String verificationCode = CryptoUtil.generateRandStr(length);
	    
	    DateTime expirationDate = DateTime.now();
	    expirationDate = expirationDate.plusMinutes(expiration);
	    smsVerification = new SmsVerification();
	    smsVerification.setMobile(mobile);
	    smsVerification.setCode(verificationCode);
	    smsVerification.setIsUsed(0);
	    smsVerification.setExpiration(expirationDate.toDate());
	    StringBuilder sb = new StringBuilder();
	    sb.append("【博士星】您的验证码为：").append(verificationCode).append("，请在30分钟内完成校验。");
	    smsVerificationMapper.insert(smsVerification);
	    smsSendService.sendSms(sb.toString(), mobile);
	    return smsVerification.getId();
	}
	
	/**
	 * 验证短信
	 */
	@Override
	@Transactional
	public Integer verificationSmsCode(String mobile, String code) {
		if(StringUtils.isEmpty(code)){
			AjkException exception = new AjkException(ErrorConstant.OPERATION_ERROR.getErrorCode(),"验证码无效");
			logger.error("验证校验失败",exception);
			throw exception;
		}
		if(StringUtils.isEmpty(mobile) || !Pattern.matches(ValidatorUtil.mobilePattern, mobile)){
			AjkException exception = new AjkException(ErrorConstant.OPERATION_ERROR.getErrorCode(),"手机号为空或格式错误");
			logger.error("验证校验失败",exception);
			throw exception;
		}
		SmsVerification verification = smsVerificationMapper.findLastByMobile(mobile);
		if(verification == null){
			AjkException exception = new AjkException(ErrorConstant.OPERATION_ERROR.getErrorCode(),"无验证码记录");
			logger.error("验证校验失败",exception);
			throw exception;
		}
		if(verification.getIsUsed()==1){
			AjkException exception = new AjkException(ErrorConstant.OPERATION_ERROR.getErrorCode(),"验证码已使用过");
			logger.error("验证校验失败",exception);
			throw exception;
		}
		//是否已经过期
		DateTime now = DateTime.now();
		if(now.isAfter(verification.getExpiration().getTime())){
			AjkException exception = new AjkException(ErrorConstant.OPERATION_ERROR.getErrorCode(),"验证码已过期");
			logger.error("验证校验失败",exception);
			throw exception;
		};
		if(!StringUtils.equals(code,verification.getCode())){
			AjkException exception = new AjkException(ErrorConstant.OPERATION_ERROR.getErrorCode(),"验证码错误");
			logger.error("验证校验失败",exception);
			throw exception;
		}
		verification.setIsUsed(1);
		smsVerificationMapper.update(verification);
		return 1;
	}

}	